package com.ssy.lingxi.report.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.report.dao.contract.ContractDAO;
import com.ssy.lingxi.report.entity.report.ContractDayReportDO;
import com.ssy.lingxi.report.model.vo.response.PurchaseStatisticsDetailVO;
import com.ssy.lingxi.report.model.vo.response.PurchaseStatisticsVO;
import com.ssy.lingxi.report.repository.report.ContractDayReportRepository;
import com.ssy.lingxi.report.service.IContractReportService;
import com.ssy.lingxi.report.utils.TimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *  合同报表接口实现
 * @author ds
 * @date 2021/6/10
 * @version 2.0.0
 */
@Service
public class ContractReportServiceImpl implements IContractReportService {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    private static final String zero_HHmmss = " 00:00:00";

    @Resource
    private ContractDayReportRepository contractDayReportRepository;

    @Resource
    private ContractDAO contractDAO;

    private static final Logger logger = LoggerFactory.getLogger(ContractReportServiceImpl.class);


    /**
     * 获取订单数据
     * @author 伍将
     * @date 2020/11/10
     * @param user:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.report.model.vo.response.OrderStatisticsVO>
     **/
    @Override
    public Wrapper<PurchaseStatisticsVO> getPurchaseList(UserLoginCacheDTO user) {
        PurchaseStatisticsVO result = new PurchaseStatisticsVO();

        DecimalFormat format = new DecimalFormat("#.00");

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
        String startDate;
        String endDate = DateUtil.date().toString("yyyy-MM-dd 23:59:59");
        LocalDateTime endTime = LocalDateTime.parse(endDate, formatter);
        List<String> timeList;

        // 查询近三十天数据
        startDate = DateUtil.offsetMonth(DateUtil.date(), -1).toString("yyyy-MM-dd 00:00:00");
        LocalDateTime monthStartTime = LocalDateTime.parse(startDate, formatter);
        List<ContractDayReportDO> weekDOList = contractDayReportRepository.getAllByDateTimeBetween(monthStartTime, endTime);
        //查询当天的数据
        List<ContractDayReportDO> todayContractDayReport = getContractDayReportList(endTime, endTime);
        if(CollectionUtil.isNotEmpty(todayContractDayReport)){
            weekDOList.add(todayContractDayReport.get(0));
        }
        timeList = TimeUtil.getBetweenDays(startDate, endDate);
        List<PurchaseStatisticsDetailVO> monthList = convertOrderDayStatistics(timeList, weekDOList);
        if (monthList.size() > 0) {

            // 设置三十日数据
            result.setMonthList(monthList);
            result.setMonthCount(monthList.stream()
                    .filter(o -> o.getDateTime().isAfter(monthStartTime) && o.getDateTime().isBefore(endTime))
                    .mapToLong(PurchaseStatisticsDetailVO::getCount).sum());
            result.setMonthAmount(
                    Double.parseDouble(format.format(
                            monthList.stream()
                                    .filter(o -> o.getDateTime().isAfter(monthStartTime) && o.getDateTime().isBefore(endTime))
                                    .mapToDouble(PurchaseStatisticsDetailVO::getAmount).sum())
                    ));

            // 设置七日数据
            startDate = DateUtil.offsetWeek(DateUtil.date(), -1).toString("yyyy-MM-dd 00:00:00");
            LocalDateTime weekStartTime = LocalDateTime.parse(startDate, formatter);
            List<PurchaseStatisticsDetailVO> weekList = monthList.stream()
                    .filter(o -> o.getDateTime().isAfter(weekStartTime) && o.getDateTime().isBefore(endTime))
                    .collect(Collectors.toList());
            result.setWeekList(weekList);
            result.setWeekCount(weekList.stream().mapToLong(PurchaseStatisticsDetailVO::getCount).sum());
            result.setWeekAmount(
                    Double.parseDouble(format.format(
                            weekList.stream().mapToDouble(PurchaseStatisticsDetailVO::getAmount).sum())
                    ));

            // 设置今日数据
            LocalDateTime todayTime = LocalDateTime.parse(DateUtil.date().toString("yyyy-MM-dd 00:00:00"), formatter);
            result.setTodayCount(weekList.stream()
                    .filter(o -> o.getDateTime().equals(todayTime))
                    .mapToLong(PurchaseStatisticsDetailVO::getCount).sum());
            result.setTodayAmount(weekList.stream()
                    .filter(o -> o.getDateTime().equals(todayTime))
                    .mapToDouble(PurchaseStatisticsDetailVO::getAmount).sum());
        }

        // 查询近一年数据
        startDate = DateUtil.offset(DateUtil.date(), DateField.YEAR, -1).toString("yyyy-MM-01 00:00:00");
        endDate = DateUtil.date().toString("yyyy-MM-01 00:00:00");
        LocalDateTime yearStartTime = LocalDateTime.parse(startDate, formatter);
        List<ContractDayReportDO> yearDOList = contractDayReportRepository.getAllByDateTimeBetween(yearStartTime, endTime);
        timeList = TimeUtil.getBetweenMonths(startDate, endDate);
        List<PurchaseStatisticsDetailVO> yearList = convertOrderMonthStatistics(timeList, yearDOList);
        // 设置近一年数据
        result.setYearList(yearList);
        //总数
        Long totalCount = contractDayReportRepository.getAllCount();
        BigDecimal totalAmount = contractDayReportRepository.getAllAmount();
        result.setTotalCount(totalCount != null ? totalCount : 0L);
        result.setTotalAmount(totalAmount != null ? totalAmount: BigDecimal.ZERO);
        return Wrapper.success(result);
    }

    /**
     * 转换订单日统计数据
     * @author 伍将
     * @date 2020/11/10
     * @param timeList:
     * @param reportDOList:
     * @return java.util.List<com.ssy.lingxi.report.model.vo.response.OrderStatisticsDetailVO>
     **/
    private List<PurchaseStatisticsDetailVO> convertOrderDayStatistics(List<String> timeList, List<ContractDayReportDO> reportDOList) {

        List<PurchaseStatisticsDetailVO> resultList = new ArrayList<>();

        if (timeList == null || timeList.size() <= 0) {
            return resultList;
        }

        Map<LocalDateTime, ContractDayReportDO> map = reportDOList.stream().collect(Collectors.toMap(ContractDayReportDO::getDateTime, Function.identity(), (key1, key2) -> key2));

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);

        // 补全时间
        for (String time : timeList) {
            PurchaseStatisticsDetailVO detailVO = new PurchaseStatisticsDetailVO();
            detailVO.setDateTime(LocalDateTime.parse(time + zero_HHmmss, formatter));
            detailVO.setCount(0L);
            detailVO.setAmount(0D);
            if (map.containsKey(detailVO.getDateTime())) {
                detailVO.setCount(map.get(detailVO.getDateTime()).getCount());
                detailVO.setAmount(map.get(detailVO.getDateTime()).getAmount());
            }
            resultList.add(detailVO);
        }

        return resultList;
    }

    /**
     * 转换订单月统计数据
     * @author 伍将
     * @date 2020/11/10
     * @param timeList:
     * @param reportDOList:
     * @return java.util.List<com.ssy.lingxi.report.model.vo.response.OrderStatisticsDetailVO>
     **/
    private List<PurchaseStatisticsDetailVO> convertOrderMonthStatistics(List<String> timeList, List<ContractDayReportDO> reportDOList) {

        List<PurchaseStatisticsDetailVO> resultList = new ArrayList<>();

        if (timeList == null || timeList.size() <= 0) {
            return resultList;
        }

        Map<LocalDateTime, ContractDayReportDO> map = reportDOList.stream().collect(Collectors.toMap(ContractDayReportDO::getDateTime, Function.identity(), (key1, key2) -> key2));

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);

        // 补全时间
        for (String time : timeList) {
            PurchaseStatisticsDetailVO detailVO = new PurchaseStatisticsDetailVO();
            detailVO.setDateTime(LocalDateTime.parse(time + zero_HHmmss, formatter));
            detailVO.setCount(0L);
            detailVO.setAmount(0D);
            if (map.containsKey(detailVO.getDateTime())) {
                detailVO.setCount(map.get(detailVO.getDateTime()).getCount());
                detailVO.setAmount(map.get(detailVO.getDateTime()).getAmount());
            }
            resultList.add(detailVO);
        }

        return resultList;
    }

    /**
     *  定时任务-生成前一天的采购统计[统计合同数据]
     * @author ds
     * @date 2021/6/11
     * @version 2.0.0
     */
    @Override
    @Transactional
    public void newlyAddedDayContractReportTask() {
        logger.info("采购统计-生成昨日采购数据-start");
        //生成昨日数据
        DateTime dateTime =DateUtil.yesterday();
        newlyAddedDayContractReportTaskByDate(dateTime,dateTime);
        logger.info("采购统计-生成昨日采购数据-end");
    }

    /**
     * 初始化采购统计
     * [初始化一年内的数据，如果已存在则不生成]
     */
    @Transactional
    public void initContractDayReport() {

        Long allCount = contractDayReportRepository.getAllCount();
        if(allCount==null||allCount<=0){
            logger.info("initContractDayReport初始化采购统计-start");
            //元旦日期
            DateTime dateTime = DateUtil.beginOfYear(DateUtil.date());
            DateTime yesterday = DateUtil.yesterday();
            //初始化一年内的数据
            newlyAddedDayContractReportTaskByDate(dateTime,yesterday);
            logger.info("initContractDayReport初始化采购统计-end");
        }
    }

    @Transactional
    public void newlyAddedDayContractReportTaskByDate(Date startDate,Date endDate ) {
        logger.info("日新增采购统计[合同]报表定时任务开启：" + dateFormat.format(new Date()));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime startTime = LocalDateTime.parse(
                DateUtil.date(startDate)
                        .toString("yyyy-MM-dd 00:00:00")
                , formatter);
        LocalDateTime endTime = LocalDateTime.parse(
                DateUtil.date(endDate)
                        .toString("yyyy-MM-dd 23:59:59")
                , formatter);
        //获取日期段内每日的合同统计数
        List<ContractDayReportDO> contractDayReportDOS = getContractDayReportList(startTime, endTime);
        //保存
        saveContractDayReport(startTime,endTime,contractDayReportDOS);
        logger.info("日新增采购统计[合同]报表定时任务结束：" + dateFormat.format(new Date()));
    }


    /**
     * 获取日期段内每日的合同统计数
     * @param startTime 开始时间
     * @param endTime 结算之际
     * @return 合同统计数
     */
    @Override
    public List<ContractDayReportDO> getContractDayReportList(LocalDateTime startTime, LocalDateTime endTime) {
        //获得毫秒时间戳
        long start = startTime.toEpochSecond(ZoneOffset.ofHours(8))*1000;
        long end = endTime.toEpochSecond(ZoneOffset.ofHours(8))*1000+999;
        // 查询新增签约合同
        List<ContractDayReportDO> brandNewlyAddedBOS = contractDAO.getNewlyAddedContractByDay(start, end);
        logger.info("统计日新增合同：{}", brandNewlyAddedBOS != null ? brandNewlyAddedBOS.size() : 0);
        return brandNewlyAddedBOS;
    }



    /**
     * 保存合同日统计数据
     * @param startTime 开始时间
     * @param endTime 截至时间
     * @param resultList 合同日统计数据
     */
    private void saveContractDayReport(LocalDateTime startTime, LocalDateTime endTime,List<ContractDayReportDO> resultList){
        logger.info("统计日新增合同-保存：{}", resultList != null ? resultList.size() : 0);
        if(CollectionUtil.isEmpty(resultList)){
            return;
        }
        // 新增前先删除数据
        contractDayReportRepository.deleteByDateTimeBetween(startTime, endTime);

        // 新增统计数据
        contractDayReportRepository.saveAll(resultList);
        logger.info("统计日新增合同-保存完成resultList:{}",resultList.size());
    }
}
